pub mod connection;
pub mod pool;
pub mod types;

pub use connection::{DatabaseConnection, ConnectionConfig};
pub use pool::ConnectionPool;
pub use types::{DatabaseType, ConnectionString};

use anyhow::Result;
use std::collections::HashMap;
use tracing::info;

/// Database manager for handling multiple database connections
#[derive(Debug)]
pub struct DatabaseManager {
    connections: HashMap<String, DatabaseConnection>,
    pools: HashMap<String, ConnectionPool>,
}

impl DatabaseManager {
    /// Create a new database manager
    pub async fn new() -> Result<Self> {
        info!("Initializing database manager");

        Ok(Self {
            connections: HashMap::new(),
            pools: HashMap::new(),
        })
    }

    /// Create a new database manager synchronously
    pub fn new_sync() -> Self {
        info!("Initializing database manager (sync)");

        Self {
            connections: HashMap::new(),
            pools: HashMap::new(),
        }
    }
    
    /// Add a new database connection
    pub async fn add_connection(&mut self, name: String, config: ConnectionConfig) -> Result<()> {
        info!("Adding database connection: {}", name);

        let connection = DatabaseConnection::new(config.clone()).await?;
        self.connections.insert(name.clone(), connection);

        // Create connection pool
        let pool = ConnectionPool::new(config).await?;
        self.pools.insert(name, pool);

        Ok(())
    }
    
    /// Get a database connection by name
    pub fn get_connection(&self, name: &str) -> Option<&DatabaseConnection> {
        self.connections.get(name)
    }
    
    /// Get a connection pool by name
    pub fn get_pool(&self, name: &str) -> Option<&ConnectionPool> {
        self.pools.get(name)
    }
    
    /// Remove a database connection
    pub async fn remove_connection(&mut self, name: &str) -> Result<()> {
        info!("Removing database connection: {}", name);
        
        if let Some(mut connection) = self.connections.remove(name) {
            connection.close().await?;
        }
        
        if let Some(pool) = self.pools.remove(name) {
            pool.close().await;
        }
        
        Ok(())
    }
    
    /// List all connection names
    pub fn list_connections(&self) -> Vec<String> {
        self.connections.keys().cloned().collect()
    }
    
    /// Test a database connection
    pub async fn test_connection(&self, config: &ConnectionConfig) -> Result<bool> {
        info!("Testing database connection");

        match DatabaseConnection::test(config).await {
            Ok(_) => {
                info!("Database connection test successful");
                Ok(true)
            }
            Err(e) => {
                tracing::error!("Database connection test failed: {}", e);
                Ok(false)
            }
        }
    }

    /// Execute a query on a specific connection
    pub async fn execute_query(&self, connection_name: &str, query: &str) -> Result<crate::query::QueryResult> {
        info!("Executing query on connection: {}", connection_name);

        let pool = self.get_pool(connection_name)
            .ok_or_else(|| anyhow::anyhow!("Connection not found: {}", connection_name))?;

        let start_time = std::time::Instant::now();

        // Execute the query based on connection type
        let connection = self.get_connection(connection_name)
            .ok_or_else(|| anyhow::anyhow!("Connection not found: {}", connection_name))?;

        let result = match connection.connection_type() {
            types::DatabaseType::PostgreSQL => {
                self.execute_postgres_query(pool, query).await?
            }
            types::DatabaseType::MySQL => {
                self.execute_mysql_query(pool, query).await?
            }
            types::DatabaseType::SQLite => {
                self.execute_sqlite_query(pool, query).await?
            }
            _ => {
                return Err(anyhow::anyhow!("Database type not supported for query execution"));
            }
        };

        let execution_time = start_time.elapsed();

        Ok(crate::query::QueryResult {
            query: query.to_string(),
            rows_affected: result.rows_affected,
            execution_time,
            columns: result.columns,
            rows: result.rows,
            error: None,
        })
    }

    /// Execute PostgreSQL query
    async fn execute_postgres_query(&self, _pool: &ConnectionPool, _query: &str) -> Result<QueryExecutionResult> {
        // For now, return a mock result
        // In a real implementation, this would execute the actual query
        Ok(QueryExecutionResult {
            rows_affected: Some(0),
            columns: vec![
                crate::query::ColumnInfo {
                    name: "mock_column".to_string(),
                    data_type: "TEXT".to_string(),
                    nullable: true,
                    primary_key: false,
                }
            ],
            rows: vec![
                vec![serde_json::Value::String("Mock PostgreSQL result".to_string())]
            ],
        })
    }

    /// Execute MySQL query
    async fn execute_mysql_query(&self, _pool: &ConnectionPool, _query: &str) -> Result<QueryExecutionResult> {
        // Mock implementation
        Ok(QueryExecutionResult {
            rows_affected: Some(0),
            columns: vec![
                crate::query::ColumnInfo {
                    name: "mock_column".to_string(),
                    data_type: "VARCHAR".to_string(),
                    nullable: true,
                    primary_key: false,
                }
            ],
            rows: vec![
                vec![serde_json::Value::String("Mock MySQL result".to_string())]
            ],
        })
    }

    /// Execute SQLite query
    async fn execute_sqlite_query(&self, _pool: &ConnectionPool, _query: &str) -> Result<QueryExecutionResult> {
        // Mock implementation
        Ok(QueryExecutionResult {
            rows_affected: Some(0),
            columns: vec![
                crate::query::ColumnInfo {
                    name: "mock_column".to_string(),
                    data_type: "TEXT".to_string(),
                    nullable: true,
                    primary_key: false,
                }
            ],
            rows: vec![
                vec![serde_json::Value::String("Mock SQLite result".to_string())]
            ],
        })
    }
}

/// Internal query execution result
struct QueryExecutionResult {
    rows_affected: Option<u64>,
    columns: Vec<crate::query::ColumnInfo>,
    rows: Vec<Vec<serde_json::Value>>,
}
